package actors

import (
	"fmt"
	"sync"
)

// BaseRole provides a basic implementation of the Role interface
type BaseRole struct {
	name         string
	description  string
	capabilities []string
	actions      map[string]Action
	mutex        sync.RWMutex
}

// NewBaseRole creates a new base role
func NewBaseRole(name, description string, capabilities []string) *BaseRole {
	return &BaseRole{
		name:         name,
		description:  description,
		capabilities: capabilities,
		actions:      make(map[string]Action),
	}
}

// GetName returns the role name
func (r *BaseRole) GetName() string {
	return r.name
}

// GetDescription returns the role description
func (r *BaseRole) GetDescription() string {
	return r.description
}

// GetCapabilities returns the role capabilities
func (r *BaseRole) GetCapabilities() []string {
	r.mutex.RLock()
	defer r.mutex.RUnlock()

	caps := make([]string, len(r.capabilities))
	copy(caps, r.capabilities)
	return caps
}

// GetActions returns all actions registered with this role
func (r *BaseRole) GetActions() []Action {
	r.mutex.RLock()
	defer r.mutex.RUnlock()

	actions := make([]Action, 0, len(r.actions))
	for _, action := range r.actions {
		actions = append(actions, action)
	}
	return actions
}

// AddAction adds a new action to the role
func (r *BaseRole) AddAction(action Action) error {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	if action == nil {
		return fmt.Errorf("cannot add nil action")
	}

	if _, exists := r.actions[action.GetName()]; exists {
		return fmt.Errorf("action %s already exists", action.GetName())
	}

	r.actions[action.GetName()] = action
	return nil
}

// OnAssign is called when the role is assigned to an agent
func (r *BaseRole) OnAssign(agent Agent) error {
	// Add all role actions to the agent
	for _, action := range r.GetActions() {
		if err := agent.AddAction(action); err != nil {
			return fmt.Errorf("failed to add action %s: %w", action.GetName(), err)
		}
	}
	return nil
}

// OnRevoke is called when the role is revoked from an agent
func (r *BaseRole) OnRevoke(agent Agent) error {
	// Base implementation does nothing
	return nil
}

// AddCapability adds a new capability to the role
func (r *BaseRole) AddCapability(capability string) {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	r.capabilities = append(r.capabilities, capability)
}

// HasCapability checks if the role has a specific capability
func (r *BaseRole) HasCapability(capability string) bool {
	r.mutex.RLock()
	defer r.mutex.RUnlock()

	for _, cap := range r.capabilities {
		if cap == capability {
			return true
		}
	}
	return false
}

// GetAction returns a specific action by name
func (r *BaseRole) GetAction(name string) (Action, bool) {
	r.mutex.RLock()
	defer r.mutex.RUnlock()

	action, exists := r.actions[name]
	return action, exists
}
